package com.weixin.engine.daily;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: test
 * @description: RSA 非对称加密算法（存在加密公钥、解密私钥） 工具类
 * @author: 闲走天涯
 * @create: 2021-08-24 11:14
 */
public class RSAUtil {
    public static Map<String, String> map = new HashMap<>();

    //秘钥位数 大小为512-1024位
    public static final int KEY_SIZE = 1024;

    /**
     * 生成秘钥对
     *
     * @throws NoSuchAlgorithmException
     */
    public static void createKey() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        //初始化密钥对生成器，密钥大小为96-1024位
        keyPairGen.initialize(KEY_SIZE, new SecureRandom());
        //生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        //私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        //公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        //公钥字符串
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        //私钥字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        //保存公钥
        map.put("publicKey", publicKeyString);
        //保存私钥
        map.put("privateKey", privateKeyString);
    }

    /**
     * RSA公钥加密
     *
     * @param encodeStr 需要加密的字符串
     * @param publicKey 公钥
     * @return 密文
     * @throws Exception
     */
    public static String encode(String encodeStr, String publicKey) {
        try {
            //公钥base64解密
            byte[] decode = Base64.decodeBase64(publicKey);
            //key工厂获取RSA对象,根据X509EncodedKeySpec生成公钥对象
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decode));
            //RSA加密
            //获取Cipher RSA对象
            Cipher cipher = Cipher.getInstance("RSA");
            //初始化
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            //base64加密
            String out = Base64.encodeBase64String(cipher.doFinal(encodeStr.getBytes(StandardCharsets.UTF_8)));
            return out;
        } catch (Exception e) {
            e.printStackTrace();
        }
        //加密失败
        return null;
    }

    /**
     * RSA解密
     *
     * @param decodeStr  密文
     * @param privateKey 私钥
     * @return 明文
     * @throws Exception
     */
    public static String decode(String decodeStr, String privateKey) {
        try {
            //密文base64解密
            byte[] bytes = Base64.decodeBase64(decodeStr.getBytes(StandardCharsets.UTF_8));
            //私钥base64解密
            byte[] decode = Base64.decodeBase64(privateKey);
            //key工厂获取RSA对象,根据PKCS8EncodedKeySpec生成公钥对象
            RSAPrivateKey priKey =
                    (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decode));
            //RSA解密
            //获取Cipher RSA对象
            Cipher cipher = Cipher.getInstance("RSA");
            //初始化
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            //解密
            String out = new String(cipher.doFinal(bytes));
            return out;
        } catch (Exception e) {
            e.printStackTrace();
        }
        //加密失败
        return null;
    }

    public static void main(String[] args) throws Exception {
        System.out.println("-------------RSA加密 非对称加密算法---开始--------");
        //RSA加密 非对称加密算法
        RSAUtil.createKey();
        String str = "你好，中国！";
        String encodeStr = RSAUtil.encode(str, RSAUtil.map.get("publicKey"));
        String decodeStr = RSAUtil.decode(encodeStr, RSAUtil.map.get("privateKey"));
        System.out.println("待加密明文：" + str);
        System.out.println("已加密密文：" + encodeStr);
        System.out.println("已解密明文：" + decodeStr);
        System.out.println("公钥：" + RSAUtil.map.get("publicKey"));
        System.out.println("秘钥：" + RSAUtil.map.get("privateKey"));
        System.out.println("公钥长度：" + RSAUtil.map.get("publicKey").length());
        System.out.println("秘钥长度：" + RSAUtil.map.get("privateKey").length());
        System.out.println("-------------RSA加密 非对称加密算法---结束--------");
    }
}